﻿#ifndef _STREAM_FIFOBUFF_H_
#define _STREAM_FIFOBUFF_H_

#include "fifo_buf.h"
#include <map>
#include <string>
#include "frame_utility.h"
using namespace std;

typedef struct _FRAME_CRT_ADDR_ 
{
	uchar_t * pHead;

	bool      bDeviHead;
	uchar_t * pHeadFragment;
	uint32_t  fragmentSz;

	uchar_t * pBody;
	uint32_t  bodySize;
	
	uchar_t * pTail;
	uint32_t  tailSize;

	uint32_t  dataPos;
	uint32_t  frameSize;
	bool      bStart;
}FRAME_CRT_ADDR;

typedef struct _FRAME_GET_ADDR_
{
	bool	  bGotBufAddr;
	uchar_t * pBufAddr;   
	uint32_t  frameSize; //整帧视频的长度
	uchar_t * pBaseBuf;
	bool      bConsume;	//是否已经消费掉,如果是给出内存地址的,会先保留不消费,待下次取数据时去消费掉
}FRMAE_GET_ADDR;

class CFrmBuf:public CFIFO_buf
{
public:
	CFrmBuf();
	~CFrmBuf();
public:
	int Open(int ch, int bufSize);
	int PutFrame(uchar_t * buf, uint32_t frameLen);
	int GetFrame(uchar_t * buf, uint32_t frameLen,bool bSkip = false);
	int GetFrameNoneHead(uchar_t * buf, uint32_t frameLen);
	uint8_t GetNextFrameType();
	int GetNextFrmSize();
	int64_t GetNextFrmTime();
	int     GetFrmBuf(FRAME_CRT_ADDR & frmAddr,uint32_t frmHeadSize,uint32_t frmSize);
protected:
	int m_channel;
	int m_frameNO;
	int64_t m_nextFrmTm;
	CFrmUtility   m_frmTool;
	RD_FRAME_H * m_pFrm;
static const int FRAME_H_LEN = BASE_FRAME_HEAD_LEN;
};

//以下的类,供多进程使用比较好
#define MAX_FRAME_SIZE    500<<20    //500KB
class CFrameBufShm
{
    public:
        CFrameBufShm();
        virtual ~CFrameBufShm();

    public:
        int Open(int userID, int ch, int bufSize, bool is_producer,char * clientName = NULL);
        int Close();
        int putFrame(uchar_t *pFrameData, uint32_t frameLen,bool bCover = true);
        int getFrame(uchar_t *pFrameData, uint32_t frameLen, int *isKeyFrame = NULL);
        uchar_t *GetBufOffset(uint32_t size, uint32_t *leaf_size, uchar_t **tail_buf);
        uchar_t *GetFreeBuf(uchar_t **tail_buf, uint32_t *leaf_size);
		int SeekTime(int64_t cur_ms,int pre_sec);

    public:

        int read(unsigned char *buf, uint32_t size,  bool bPeek);
        int write(unsigned char *buf, uint32_t data_size);
        int read_pos(uint32_t offset, unsigned char *buf, uint32_t size, bool bConsume);

        void reset(uint32_t file_offset);

        int ConsumeBuf(uint32_t size);

        int ProductBuf(uint32_t size);

        //生产一个空帧去补齐．
        int ProducEmptyFrm(uint32_t size);

		//镜像帧头,便于读取帧
		int MirrorFrameHead();

#ifndef _WIN32
        int DestryMemory();
#endif
        uint32_t GetDataSize();

        uint32_t GetFreeSize()
        {
            return  m_shmSize - GetDataSize();
        }

        uint32_t GetNextFrmSize()
        {
            return m_pInfo->m_nextFrmSize;
        }

        int64_t GetNextFrmTime()
        {
            return m_pInfo->m_nextFrmTime;
        }

    protected:
        int read_buf(uint32_t offset, unsigned char *buf, uint32_t size, bool bConsume);
		int reg_user(char* userName);
		int unreg_user(char* userName);
    public:
        void SetFileOffsset(uint32_t offset)
        {
            m_pInfo->m_file_offset = offset;
        }

        uint32_t GetFIFOSize()
        {
            return  m_shmSize;
        }

        bool IsEmpty()
        {
            return ( m_pInfo->m_pidx ==  m_pInfo->m_cidx);
        }

        uint32_t GetCurWarter()
        {
            return  (GetDataSize() * 100) / m_shmSize;
        }

        bool IsOpen()
        {
            return m_bOpened;
        }

        uint32_t GetFileOffset()
        {
            return m_pInfo->m_file_offset;
        }
        int GetChannel()
        {
            return m_channel;
        }

        bool IsDataErr()
        {
            return m_pInfo->m_dataErr;
        }

        void ClearErrFlag()
        {
            m_pInfo->m_dataErr = 0;
        }


    protected:
#ifndef _WIN32
        struct flock *file_lock(short type, short whence);
#endif
        void lock();
        void unlock();
        void *CreateShm(const char *name, int size);
        static const uint32_t FRAME_HEADLEN;
    private:
        //pthread_mutex_t* mMutex;

        unsigned char *m_pShareMem;
        char m_shmName[40];
		string m_clientName;
        bool m_bOpened;
        bool m_accessMode;

        int m_shmSize;
        int m_clientID;
        int m_channel;
        int m_lockFd;
        int m_fd;
		int m_clientIdx;
#ifdef _WIN32
        HANDLE m_hMapFile;
        CCross_Lock m_lock;
#else

#endif
    protected:
        typedef struct _SHARE_BUF_INFO_
        {
			char     clientName[12];
            bool	 m_bOverWrite;
            uint32_t m_pidx;		//product index
            uint32_t m_cidx;	    //consume index
            uint32_t m_buf_size;	//

            int64_t  m_nextFrmTime;
            uint32_t m_file_offset;	//
            uint32_t m_nextFrmSize;
            bool     m_dataErr;
        } SHARE_BUF_INFO;
		SHARE_BUF_INFO *m_pInfoBase;
        SHARE_BUF_INFO *m_pInfo;
        uchar_t        *m_buf;
		CFrmUtility     m_frmTool;
};

typedef enum
{
    ERR_FRAMEFIFO_OVERDATA  = -8008,
    ERR_FRAMEFIFO_SIZE      = -8007,
    ERR_FRAMEFIFO_NOTENOUGH = -8006,
    ERR_FRAMEFIFO_NODATA    = -8005,
    ERR_FRAMEFIFO_OPENED    = -8004,
    ERR_FRAMEFIFO_NOOPEN	= -8003,
    ERR_FRAMEFIFO_PARAM     = -8002,
    ERR_FRAMEFIFO_TIMEOUT   = -8001,
    ERR_FRAMEFIFO_CREATE    = -8000,
    ERR_FRAMEFIFO_NO_EER    = 0,
} ERR_FRAME_FIFO_E;
typedef std::map<uint32_t, CFrameBufShm> MP_FRAMEBUF_T;

#define REPLAY_BUF_SZIE	 (1 * (1<<20) )
#define MAX_CLIENT_NUM    8
#define MAX_CLIENT_NAME_LEN 12
#define LOCAL_USER_0     "producer" 

#endif  //_STREAM_FIFOBUFF_H_